package light3d;


public class Point3D
{
	protected double tempX, tempY, tempZ;
	protected double rX, rY, rZ;
	protected double lX, lY, lZ;
	protected double origX, origY, origZ;
	protected double origRX, origRY, origRZ;
	protected double tU,tV;
	public int color;

	//Constructors
	private void initializePoint(double x, double y, double z)
	{
		color = -1;
		tempX = x;
		tempY = y;
		tempZ = z;
		origRX = 0;
		origRY = 0;
		origRZ = 0;
		rX = 0;
		rY = 0;
		rZ = 0;
		rotate(0,0,0);
		this.finalizeCoordinates();
	}
	public Point3D(double x, double y, double z)
	{
		this.initializePoint(x,y,z);
	}
	public Point3D()
	{
		this.initializePoint(0, 0, 0);
	}

	//Transformations
	public void translate(double x, double y, double z)
	{
		tempX += x;
		tempY += y;
		tempZ += z;
	}
	public void rotate(double x, double y, double z) 
	{
    double sX = FastMath.sin(x), cX = FastMath.cos(x),
           sY = FastMath.sin(y), cY = FastMath.cos(y),
           sZ = FastMath.sin(z), cZ = FastMath.cos(z);

    if (y != 0)
    {
      rY += y;
      double invR = FastMath.invSqrt(FastMath.pow2(tempX) + FastMath.pow2(tempZ));
      double r = 1.0 / invR;
      tempX *= invR;
      tempZ *= invR;
      double tempX2 = ((tempX * cY) - (tempZ * sY)) * r;
      tempZ = ((tempZ * cY) + (tempX * sY)) * r;
      tempX = tempX2;
    }

    if (x != 0)
    {
      double invR = FastMath.invSqrt(FastMath.pow2(tempZ) + FastMath.pow2(tempY));
      double r = 1.0 / invR;
      tempZ *= invR;
      tempY *= invR;
      double tempZ2 = ((tempZ * cX) - (tempY * sX)) * r;
      tempY = ((tempY * cX) + (tempZ * sX)) * r;
      tempZ = tempZ2;
    }

    if (z != 0)
    {
      double invR = FastMath.invSqrt(FastMath.pow2(tempX) + FastMath.pow2(tempY));
      double r = 1.0 / invR;
      tempX *= invR;
      tempY *= invR;
      double tempX2 = ((tempX * cZ) - (tempY * sZ)) * r;
      tempY = ((tempY * cZ) + (tempX * sZ)) * r;
      tempX = tempX2;
    }
	}
	public Boolean projectPoint(double nearClip, double farClip)
	{
		// Projects the point from 3D to 2D, retaining the Z;
		if (tempZ != 0)
		{
			tempX /= tempZ;
			tempY /= tempZ;
		}
		else
		{
			tempX = 0;
			tempY = 0;
		}
		return ((tempZ > nearClip) && (tempZ < farClip));
	}
	public void setPosition(double x, double y, double z)
	{
		tempX = x;
		tempY = y;
		tempZ = z;
	}
	public void scaleByScreen(double x, double y)
	{
		tempX *= x;
		tempY *= y;
	}
	//Returners
	public double getX()
	{
		return tempX;
	}
	public double getY()
	{
		return tempY;
	}
	public double getZ()
	{
		return tempZ;
	}
	public double getRX()
	{
		return rX;
	}
	public double getRY()
	{
		return rY;
	}
	public double getRZ()
	{
		return rZ;
	}
	public double getU()
	{
		return tU;
	}
	public double getV()
	{
		return tV;
	}
	public void setX(double x)
	{
		tempX = x;
	}
	public void setY(double y)
	{
		tempY = y;
	}
	public void setZ(double z)
	{
		tempZ = z;
	}
	public void setUV(double u, double v)
	{
		tU = u;
		tV = v;
	}
	//Used to reset a points transformations or save them
	public void finalizeCoordinates()
	{
		origX = tempX;
		origY = tempY;
		origZ = tempZ;
		origRX = rX;
		origRY = rY;
		origRZ = rZ;
	}
	public void resetChanges()
	{
		tempX = origX;
		tempY = origY;
		tempZ = origZ;
		rX = 0;
		rY = 0;
		rZ = 0;
		rotate(origRX, origRY, origRZ);
	}
	public Point3D clone()
	{
		Point3D c = new Point3D(origX, origY, origZ);
		c.finalizeCoordinates();
		
		c.tempX = this.tempX;
		c.tempY = this.tempY;
		c.tempZ = this.tempZ;
		
		c.rX = this.rX;
		c.rY = this.rY;
		c.rZ = this.rZ;
		
		c.tU = this.tU;
		c.tV = this.tV;
		c.color = color;
		
		return c;
	}
	public void loadUV(Point3D b)
	{
		this.tU = b.getU();
		this.tV = b.getV();
	}
	public void translateUV(double u, double v)
	{
		this.tU += u;
		this.tV += v;
	}
	public Point3D add(Point3D b)
	{
		return new Point3D(tempX + b.getX(), tempY + b.getY(), tempZ + b.getZ());
	}
	public Point3D subtract(Point3D b)
	{
		return new Point3D(tempX - b.getX(), tempY - b.getY(), tempZ - b.getZ());
	}
	public void normalize()
	{
		double l = Math.sqrt(FastMath.pow2(tempX) + FastMath.pow2(tempY) + FastMath.pow2(tempZ));
		tempX /= l;
		tempY /= l;
		tempZ /= l;
	}
}
